﻿<h1>反射</h1>

<p>
Go是一门具有良好反射支持的静态语言。
本文将解释<code>reflect</code>标准库包中提供的反射功能。
</p>

<p>
在阅读本剩下的部分之前，最好先阅读<a href="type-system-overview.html">Go类型系统概述</a>和<a href="interface.html">接口</a>两篇文章。
</p>

<h3>反射概述</h3>

<p>
从<a href="generic.html">上一篇文章</a>中，我们得知目前Go缺少自定义范型支持。
Go中提供的的反射功能带来了很多动态特性，从而从一定程度上弥补了Go缺少自定义范型而导致的不便（尽管反射比范型的运行效率低）。
很多标准库，比如<code>fmt</code>和很多<code>encoding</code>包，均十分依赖于反射机制。
</p>

<p>
我们可以通过<code>reflect</code>库包中<code>Type</code>和<code>Value</code>两个类型提供的功能来观察不同的Go值。
下面紧接着的两节将介绍如何使用这两个类型。
</p>

<p>
Go反射机制设计的目标之一是任何非反射操作都可以通过反射机制来完成。
由于各种各样的原因，此目标目前（Go 1.13）并没有得到100%的实现。
但是，目前大部分的非反射操作都可以通过反射机制来完成。
另一方面，通过反射，我们也可以完成一些使用非反射操作不可能完成的操作。
不能或者只能通过反射完成的操作将在下面的讲解中提及。
</p>

<h3><code>reflect.Type</code>类型和值</h3>

<div>
<p>
通过调用<code>reflect.TypeOf</code>函数，我们可以从一个任何非接口类型的值创建一个<code>reflect.Type</code>值。
此<code>reflect.Type</code>值表示着此非接口值的类型。通过此值，我们可以得到很多此非接口类型的信息。
当然，我们也可以将一个接口值传递给一个<code>reflect.TypeOf</code>函数调用，但是此调用将返回一个表示着此接口值的动态类型的<code>reflect.Type</code>值。
实际上，<code>reflect.TypeOf</code>函数的唯一参数的类型为<code>interface{}</code>，
<code>reflect.TypeOf</code>函数将总是返回一个表示着此唯一接口参数值的动态类型的<code>reflect.Type</code>值。
那如何得到一个表示着某个接口类型的<code>reflect.Type</code>值呢？
我们必须通过下面将要介绍的一些间接途径来达到这一目的。
</p>

<p>
类型<code>reflect.Type</code>为一个接口类型，它指定了<a href="https://golang.google.cn/pkg/reflect/#Type">若干方法</a>。
通过这些方法，我们能够观察到一个<code>reflect.Type</code>值所表示的Go类型的各种信息。
这些方法中的有的适用于<a href="https://golang.google.cn/pkg/reflect/#Kind">所有种类</a>的类型，有的只适用于一种或几种类型。
通过不合适的<code>reflect.Type</code>属主值调用某个方法将在运行时产生一个恐慌。
请阅读<code>reflect</code>代码库中各个方法的文档来获取如何正确地使用这些方法。
</p>

一个例子：

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	type A = [16]int16
	var c <-chan map[A][]byte
	tc := reflect.TypeOf(c)
	fmt.Println(tc.Kind())    // chan
	fmt.Println(tc.ChanDir()) // <-chan
	tm := tc.Elem()
	ta, tb := tm.Key(), tm.Elem()
	fmt.Println(tm.Kind(), ta.Kind(), tb.Kind()) // map array slice
	tx, ty := ta.Elem(), tb.Elem()

	// byte是uint8类型的别名。
	fmt.Println(tx.Kind(), ty.Kind()) // int16 uint8
	fmt.Println(tx.Bits(), ty.Bits()) // 16 8
	fmt.Println(tx.ConvertibleTo(ty)) // true
	fmt.Println(tb.ConvertibleTo(ta)) // false

	// 切片类型和映射类型都是不可比较类型。
	fmt.Println(tb.Comparable()) // false
	fmt.Println(tm.Comparable()) // false
	fmt.Println(ta.Comparable()) // true
	fmt.Println(tc.Comparable()) // true
}
</code></pre>

<p>
目前，Go支持<a href="https://golang.google.cn/pkg/reflect/#Kind">26种类型</a>。
</p>

在上面这个例子中，我们使用方法<code>Elem</code>来得到某些类型的元素类型。
实际上，此方法也可以用来得到一个指针类型的基类型。一个例子：

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

type T []interface{m()}
func (T) m() {}

func main() {
	tp := reflect.TypeOf(new(interface{}))
	tt := reflect.TypeOf(T{})
	fmt.Println(tp.Kind(), tt.Kind()) // ptr slice

	// 使用间接的方法得到表示两个接口类型的reflect.Type值。
	ti, tim := tp.Elem(), tt.Elem()
	fmt.Println(ti.Kind(), tim.Kind()) // interface interface

	fmt.Println(tt.Implements(tim))  // true
	fmt.Println(tp.Implements(tim))  // false
	fmt.Println(tim.Implements(tim)) // true

	// 所有的类型都实现了任何空接口类型。
	fmt.Println(tp.Implements(ti))  // true
	fmt.Println(tt.Implements(ti))  // true
	fmt.Println(tim.Implements(ti)) // true
	fmt.Println(ti.Implements(ti))  // true
}
</code></pre>

<p>
上面这个例子同时也展示了如何通过间接的途径得到一个表示一个接口类型的<code>reflect.Type</code>值。
</p>

我们可以通过反射列出一个类型的所有（导出）方法和一个结构体类型的所有字段。
我们也可以通过反射列出一个函数类型的各个输入参数和返回结果类型。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

type F func(string, int) bool
func (f F) Validate(s string) bool {
	return f(s, 32)
}

func main() {
	var x struct {
		n int
		f F
	}
	tx := reflect.TypeOf(x)
	fmt.Println(tx.Kind())     // struct
	fmt.Println(tx.NumField()) // 2
	tf := tx.Field(1).Type
	fmt.Println(tf.Kind())               // func
	fmt.Println(tf.IsVariadic())         // false
	fmt.Println(tf.NumIn(), tf.NumOut()) // 2 1
	fmt.Println(tf.NumMethod())          // 1
	ts, ti, tb := tf.In(0), tf.In(1), tf.Out(0)
	fmt.Println(ts.Kind(), ti.Kind(), tb.Kind()) // string int bool
}
</code></pre>

<p>
注意：<code>reflect.Type.NumMethod</code>方法只返回一个类型的所有导出的方法的个数。
</p>

<code>reflect</code>代码包也提供了一些其它函数来动态地创建出来一些非定义组合类型。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	ta := reflect.ArrayOf(5, reflect.TypeOf(123))
	fmt.Println(ta) // [5]int
	tc := reflect.ChanOf(reflect.SendDir, ta)
	fmt.Println(tc) // chan<- [5]int
	tp := reflect.PtrTo(ta)
	fmt.Println(tp) // *[5]int
	ts := reflect.SliceOf(tp)
	fmt.Println(ts) // []*[5]int
	tm := reflect.MapOf(ta, tc)
	fmt.Println(tm) // map[[5]int]chan<- [5]int
	tf := reflect.FuncOf([]reflect.Type{ta},
				[]reflect.Type{tp, tc}, false)
	fmt.Println(tf) // func([5]int) (*[5]int, chan<- [5]int)
	tt := reflect.StructOf([]reflect.StructField{
		{Name: "Age", Type: reflect.TypeOf("abc")},
	})
	fmt.Println(tt)            // struct { Age string }
	fmt.Println(tt.NumField()) // 1
}
</code></pre>

<p>
</p>

<p>
上面的例子并未展示和<code>reflect.Type</code>相关的的所有函数和方法。
请阅读<code>reflect</code>标准库代码包的文档以获取如何使用这些函数和方法。
</p>

<p>
注意，到目前为止（Go 1.13），我们无法通过反射动态创建一个接口类型。这是Go反射目前的一个限制。
</p>

<p>
另一个限制是使用反射动态创建结构体类型的时候可能会有各种不完美的情况出现。
</p>

<p>
第三个限制是我们无法通过反射来声明一个新的类型。
</p>

</div>

<h3><code>reflect.Value</code>类型和值</h3>

<div>
<p>
类似的，我们可以通过调用<code>reflect.ValueOf</code>函数，从一个非接口类型的值创建一个<code>reflect.Value</code>值。
此<code>reflect.Value</code>值代表着此非接口值。
和<code>reflect.TypeOf</code>函数类似，<code>reflect.ValueOf</code>函数也只有一个<code>interface{}</code>类型的参数。
当我们将一个接口值传递给一个<code>reflect.ValueOf</code>函数调用时，此调用返回的是代表着此接口值的动态值的一个<code>reflect.Value</code>值。
我们必须通过间接的途径获得一个代表一个接口值的<code>reflect.Value</code>值。
</p>

<p>
被一个<code>reflect.Value</code>值代表着的值常称为此<code>reflect.Value</code>值的底层值（underlying value）。
</p>

<p>
<code>reflect.Value</code>类型有<a href="https://golang.google.cn/pkg/reflect/">很多方法</a>。
我们可以调用这些方法来观察和操纵一个<code>reflect.Value</code>属主值表示的Go值。
这些方法中的有些适用于所有种类类型的值，有些只适用于一种或几种类型的值。
通过不合适的<code>reflect.Value</code>属主值调用某个方法将在运行时产生一个恐慌。
请阅读<code>reflect</code>代码库中各个方法的文档来获取如何正确地使用这些方法。
</p>

<p>
一个<code>reflect.Value</code>值的<code>CanSet</code>方法将返回此<code>reflect.Value</code>值代表的Go值是否可以被修改（可以被赋值）。
如果一个Go值可以被修改，则我们可以调用对应的<code>reflect.Value</code>值的<code>Set</code>方法来修改此Go值。
注意：<code>reflect.ValueOf</code>函数直接返回的<code>reflect.Value</code>值都是不可修改的。
</p>

一个例子：

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	n := 123
	p := &n
	vp := reflect.ValueOf(p)
	fmt.Println(vp.CanSet(), vp.CanAddr()) // false false
	vn := vp.Elem() // 取得vp的底层指针值引用的值的代表值
	fmt.Println(vn.CanSet(), vn.CanAddr()) // true true
	vn.Set(reflect.ValueOf(789)) // <=> vn.SetInt(789)
	fmt.Println(n)               // 789
}
</code></pre>

<p>
</p>

一个结构体值的非导出字段不能通过反射来修改。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	var s struct {
		X interface{} // 一个导出字段
		y interface{} // 一个非导出字段
	}
	vp := reflect.ValueOf(&s)
	// 如果vp代表着一个指针，下一行等价于"vs := vp.Elem()"。
	vs := reflect.Indirect(vp)
	// vx和vy都各自代表着一个接口值。
	vx, vy := vs.Field(0), vs.Field(1)
	fmt.Println(vx.CanSet(), vx.CanAddr()) // true true
	// vy is addressable but not modifiable.
	fmt.Println(vy.CanSet(), vy.CanAddr()) // false true
	vb := reflect.ValueOf(123)
	vx.Set(vb)     // okay, 因为vx代表的值是可修改的。
	// vy.Set(vb)  // 会造成恐慌，因为vy代表的值是不可修改的。
	fmt.Println(s) // {123 &lt;nil&gt;}
	fmt.Println(vx.IsNil(), vy.IsNil()) // false true
}
</code></pre>

<p>
上例中同时也展示了如何间接地获取底层值为接口值的<code>reflect.Value</code>值。
</p>

从上两例中，我们可以得知有两种方法获取一个代表着一个指针所引用着的值的<code>reflect.Value</code>值：
<ol>
<li>
	通过调用代表着被此指针值的<code>reflect.Value</code>值的<code>Elem</code>方法。
</li>
<li>
	将代表着被此指针值的<code>reflect.Value</code>值的传递给一个<code>reflect.Indirect</code>函数调用。
	（如果传递给一个<code>reflect.Indirect</code>函数调用的实参不代表着一个指针值，则此调用返回此实参的一个复制。）
</li>
</ol>

注意：<code>reflect.Value.Elem</code>方法也可以用来获取一个代表着一个接口值的动态值的<code>reflect.Value</code>值，比如下例中所示。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	var z = 123
	var y = &z
	var x interface{} = y
	v := reflect.ValueOf(&x)
	vx := v.Elem()
	vy := vx.Elem()
	vz := vy.Elem()
	vz.Set(reflect.ValueOf(789))
	fmt.Println(z) // 789
}
</code></pre>

<p>
</p>

<code>reflect</code>标准库包中也提供了一些对应着内置函数或者各种非反射功能的函数。
下面这个例子展示了如何利用这些函数将一个自定义范型函数绑定到不同的类型的函数值上。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func InvertSlice(args []reflect.Value) (result []reflect.Value) {
	inSlice, n := args[0], args[0].Len()
	outSlice := reflect.MakeSlice(inSlice.Type(), 0, n)
	for i := n-1; i >= 0; i-- {
		element := inSlice.Index(i)
		outSlice = reflect.Append(outSlice, element)
	}
	return []reflect.Value{outSlice}
}

func Bind(p interface{}, f func ([]reflect.Value) []reflect.Value) {
	// invert代表着一个函数值。
	invert := reflect.ValueOf(p).Elem()
	invert.Set(reflect.MakeFunc(invert.Type(), f))
}

func main() {
	var invertInts func([]int) []int
	Bind(&invertInts, InvertSlice)
	fmt.Println(invertInts([]int{2, 3, 5})) // [5 3 2]

	var invertStrs func([]string) []string
	Bind(&invertStrs, InvertSlice)
	fmt.Println(invertStrs([]string{"Go", "C"})) // [C Go]
}
</code></pre>

<p>
</p>

如果一个<code>reflect.Value</code>值的底层值为一个函数值，则我们可以调用此<code>reflect.Value</code>值的<code>Call</code>方法来调用此函数。
每个<code>Call</code>方法调用接受一个<code>[]reflect.Value</code>类型的参数（表示传递给相应函数调用的各个实参）并返回一个同类型结果（表示相应函数调用返回的各个结果）。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

type T struct {
	A, b int
}

func (t T) AddSubThenScale(n int) (int, int) {
	return n * (t.A + t.b), n * (t.A - t.b)
}

func main() {
	t := T{5, 2}
	vt := reflect.ValueOf(t)
	vm := vt.MethodByName("AddSubThenScale")
	results := vm.Call([]reflect.Value{reflect.ValueOf(3)})
	fmt.Println(results[0].Int(), results[1].Int()) // 21 9

	neg := func(x int) int {
		return -x
	}
	vf := reflect.ValueOf(neg)
	fmt.Println(vf.Call(results[:1])[0].Int()) // -21
	fmt.Println(vf.Call([]reflect.Value{
		vt.FieldByName("A"), // 如果是字段b，则造成恐慌
	})[0].Int()) // -5
}
</code></pre>

<p>
请注意：非导出结构体字段值不能用做反射函数调用中的实参。
如果上例中的<code>vt.FieldByName("A")</code>被替换为<code>vt.FieldByName("b")</code>，则将产生一个恐慌。
</p>

下面是一个使用映射反射值的例子。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	vakueOf := reflect.ValueOf
	m := map[string]int{"Unix": 1973, "Windows": 1985}
	v := vakueOf(m)
	// 第二个实参为Value零值时，表示删除一个映射条目。
	v.SetMapIndex(vakueOf("Windows"), reflect.Value{})
	v.SetMapIndex(vakueOf("Linux"), vakueOf(1991))
	for i := v.MapRange(); i.Next(); {
		fmt.Println(i.Key(), "\t:", i.Value())
	}
}
</code></pre>

<p>
注意：方法<code>reflect.Value.MapRange</code>方法是从Go 1.12开始才支持的。
</p>

下面是一个使用通道反射值的例子。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	c := make(chan string, 2)
	vc := reflect.ValueOf(c)
	vc.Send(reflect.ValueOf("C"))
	succeeded := vc.TrySend(reflect.ValueOf("Go"))
	fmt.Println(succeeded) // true
	succeeded = vc.TrySend(reflect.ValueOf("C++"))
	fmt.Println(succeeded) // false
	fmt.Println(vc.Len(), vc.Cap()) // 2 2
	vs, succeeded := vc.TryRecv()
	fmt.Println(vs.String(), succeeded) // C true
	vs, sentBeforeClosed := vc.Recv()
	fmt.Println(vs.String(), sentBeforeClosed) // Go false
	vs, succeeded = vc.TryRecv()
	fmt.Println(vs.String()) // &lt;invalid Value&gt;
	fmt.Println(succeeded)   // false
}
</code></pre>

<p>
<code>reflect.Value</code>类型的<code>TrySend</code>和<code>TryRecv</code>方法对应着只有一个<code>case</code>分支和一个<code>default</code>分支的<a href="channel.html#select"><code>select</code>流程控制代码块</a>。
</p>

我们可以使用<code>reflect.Select</code>函数在运行时刻来模拟具有不定<code>case</code>分支数量的<code>select</code>流程控制代码块。

<pre class="line-numbers"><code class="language-go">package main

import "fmt"
import "reflect"

func main() {
	c := make(chan int, 1)
	vc := reflect.ValueOf(c)
	succeeded := vc.TrySend(reflect.ValueOf(123))
	fmt.Println(succeeded, vc.Len(), vc.Cap()) // true 1 1

	vSend, vZero := reflect.ValueOf(789), reflect.Value{}
	branches := []reflect.SelectCase{
		{Dir: reflect.SelectDefault, Chan: vZero, Send: vZero},
		{Dir: reflect.SelectRecv, Chan: vc, Send: vZero},
		{Dir: reflect.SelectSend, Chan: vc, Send: vSend},
	}
	selIndex, vRecv, closed := reflect.Select(branches)
	fmt.Println(selIndex)    // 1
	fmt.Println(closed)      // true
	fmt.Println(vRecv.Int()) // 123
	vc.Close()
	// 再模拟select流程控制代码块。因为vc已经关闭了，
	// 所以需将最后一个case分支去除，否则它可能会造成一个恐慌。
	selIndex, _, closed = reflect.Select(branches[:2])
	fmt.Println(selIndex, closed) // 1 false
}
</code></pre>

<p>
</p>

一些<code>reflect.Value</code>值可能表示着不合法的Go值。
这样的值为<code>reflect.Value</code>类型的零值（即没有底层值的<code>reflect.Value</code>值）。

<pre class="line-numbers"><code class="language-go">package main

import "reflect"
import "fmt"

func main() {
	var z reflect.Value // 一个reflect.Value零值
	fmt.Println(z)      // &lt;invalid reflect.Value&gt;
	v := reflect.ValueOf((*int)(nil)).Elem()
	fmt.Println(v)      // &lt;invalid reflect.Value&gt;
	fmt.Println(v == z) // true
	var i = reflect.ValueOf([]interface{}{nil}).Index(0)
	fmt.Println(i)             // &lt;nil&gt;
	fmt.Println(i.Elem())      // &lt;invalid reflect.Value&gt;
	fmt.Println(i.Elem() == z) // true
}
</code></pre>

<p>
</p>

从上面的例子中，我们知道，使用空接口<code>interface{}</code>值做为中介，一个Go值可以转换为一个<code>reflect.Value</code>值。
逆过程类似，通过调用一个<code>reflect.Value</code>值的<code>Interface</code>方法得到一个<code>interface{}</code>值，然后将此<code>interface{}</code>断言为原来的Go值。

<pre class="line-numbers"><code class="language-go">package main

import "reflect"
import "fmt"

func main() {
	vx := reflect.ValueOf(123)
	vy := reflect.ValueOf("abc")
	vz := reflect.ValueOf([]bool{false, true})

	x := vx.Interface().(int)
	y := vy.Interface().(string)
	z := vz.Interface().([]bool)
	fmt.Println(x, y, z) // 123 abc [false true]
}
</code></pre>

<p>
</p>

<p>
从Go 1.13开始，我们可以使用<code>Value.IsZero</code>方法来查看一个值是否为零值。
</p>

<a class="anchor" id="deep-equal"></a>
<p>
上面这些例子并未触及到所有的和<code>reflect.Value</code>相关的函数和方法，请阅读<code>reflect</code>标准库包的文档以获取如何使用这些函数和方法。
另外请注意<a href="details.html">Go细节101</a>中提到的<a href="details.html#reflect-deep-equal">一些</a>关于<a href="details.html#reflect-value-bytes">反射的细节</a>。
</p>

</div>



<!--

bug setcion in reflect docs

interface type numbe methods, non-exported, ...


https://github.com/golang/go/issues/15924
https://github.com/golang/go/issues/16522
https://github.com/golang/go/issues/20824

https://github.com/golang/go/issues/22073

https://github.com/golang/go/issues/22075
* bug on reflect query method of interface type and value

https://github.com/golang/go/issues/22143

https://github.com/golang/go/issues/20541

https://github.com/golang/go/issues/20013



https://groups.google.com/forum/#!msg/golang-dev/coyYwxU3dfM/K_nSPAbOY4kJ;context-place=searchin/golang-dev/closure$20$20callable$20pointer%7Csort:date

reflect.StructOf: StructOf currently does not generate wrapper methods for embedded fields.
                  This limitation may be lifted in a future version.

reflect.StructOf: anonymous fileds: will not produce methods table

https://github.com/golang/go/issues/15924

https://github.com/golang/go/issues/24781

https://github.com/golang/go/issues/20633
https://github.com/golang/go/issues/20632
https://github.com/golang/go/issues/20824

https://github.com/golang/go/issues/24782
* https://play.golang.org/p/Kd4igw-vOp7
* https://play.golang.org/p/KCvFWtWRC1b

https://github.com/golang/go/issues/25400 (not a bug)
https://github.com/golang/go/issues/25401
https://github.com/golang/go/issues/25402
https://github.com/golang/go/issues/25403

https://github.com/golang/go/issues/28761
https://github.com/golang/go/issues/28748

============================================




================

reflectutil
* UnderlyingTypeOf(.)
* IsZeroValue(.)
  make using of reflect.Zero(type)

======================

generally, reflect can do any things non-reflect ways can do (not including the unsafe ways)
reflect even can do non-relfect ways can't do.
* SetLen and SetCap
* select any number of cases
* get the kind of a value
* convert []MyByte to []byte

-->
